package pers.mor.tomcat.catalina;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.LogFactory;
import cn.hutool.system.SystemUtil;
import pers.mor.tomcat.watcher.DynamicDeployWatcher;

import java.io.*;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;

public class Host {

    private String name;
    private String appBase;
    private boolean reloadable = false;
    private boolean dynamicDeploy = false;
    private DynamicDeployWatcher dynamicDeployWatcher;
    private String absoluteAppBase;
    private Map<String, Context> contextMap;

    public Host(String name, String appBase, boolean reloadable, boolean dynamicDeploy) {
        this.name = name;
        this.appBase = appBase;
        this.reloadable = reloadable;
        this.dynamicDeploy = dynamicDeploy;
        this.contextMap = new HashMap<>();
        this.scanContextOnWebappsFolder();
        this.dynamicDeploy(this.dynamicDeploy);
    }

    private void scanContextOnWebappsFolder() {
        String userDir = SystemUtil.get("user.dir");
        File file = new File(userDir, this.appBase);
        this.absoluteAppBase = file.getAbsolutePath();
        if (this.appBase == null || this.appBase.trim().equals("")) {
            LogFactory.get().error("发现 appBase = {} 请检查 server.xml 中 <Host> 是否正确配置 appBase 属性", this.appBase);
            LogFactory.get().error("自动扫描: {} 目录下未发现 webapp 应用服务", file.getAbsolutePath());
            return;
        }
        File[] children = file.listFiles();

        if (children == null) {
            return;
        }

        boolean flag = false;
        for (File child : children) {

            String childName = child.getName();
            if (childName.endsWith(".war") && !childName.trim().equals(".war")) {
                this.parseWebapp_war(child);
            }

            if (childName.equals("ROOT")) {
                flag = true;
            }
            loadContext(child);
        }

        if (flag == false) {
            LogFactory.get().warn("发现 {} 目录下 ROOT 目录缺失，无法提供默认的欢迎页服务",this.appBase);
            LogFactory.get().warn("请在默认的webapps目录下将 ROOT 目录复制至当前 Host 虚拟主机的 {} 目录中。",this.appBase);
        }
    }

    public void parseWebapp_war(File warFile) {

        String fullName = warFile.getName();
        String name = StrUtil.subBefore(fullName, ".", true);

        if (this.contextMap.get(name) != null) {
            return;
        }

        File webapps = new File(SystemUtil.get("user.dir"), this.appBase);
        File file = new File(webapps, name);

        // 开始解压
        this.decompression_war(warFile, file);
        // 加载webapp应用，创建context实例
        this.loadContext(file);
    }

    private void decompression_war(File warFile, File file) {
        // 为即将解压的war包创建同名目录
        file.mkdir();
        // 准备即将解压的war包的目标路径全名称
        File ectype = new File(file, warFile.getName());
        try{
            // 等待硬盘写入完成再执行Files.copy()
            Thread.sleep(1500);
            // 将war包复制一份同名副本至同名目录
            Files.copy(warFile.toPath(), ectype.toPath());
        } catch (IOException e) {
            String msg = StrUtil.format("解压失败:\r\n复制: {} 副本时失败", warFile.getAbsolutePath());
            LogFactory.get().error(msg);
            throw new RuntimeException(msg, e);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try{
            String cmd = "jar xvf " + warFile.getName();
            // 执行解压命令
            Process p = Runtime.getRuntime().exec(cmd, null, file);
            p.waitFor();
        } catch (IOException e) {
            String msg = StrUtil.format("解压命令: jar xvf {} 执行失败", warFile.getName());
            LogFactory.get().error(msg);
            throw new RuntimeException(msg, e);
        } catch (InterruptedException e) {
            this.delete(file);
            this.decompression_war(warFile, file);
        }
        // 解压完成后删除副本
        ectype.delete();
    }

    private boolean delete(File file) {
        File[] files = file.listFiles();
        if (files == null || files.length == 0) {
            return file.delete();
        }
        for (File f : files) {
            delete(f);
        }
        return file.delete();
    }

    private void loadContext(File child) {
        String path = child.getName();
        if (path.equals("ROOT")) {
            path = "/";
        } else {
            path = "/" + path;
        }
        String base = child.getAbsolutePath();
        Context context = new Context(path, base, this, this.reloadable);
        this.contextMap.put(context.getPath(), context);
    }

    private void dynamicDeploy(boolean dynamic) {
        if (dynamic == true) {
            this.dynamicDeployWatcher = new DynamicDeployWatcher(this);
            this.dynamicDeployWatcher.start();
        }
    }

    public void reload(Context oldContext) {
        String path = oldContext.getPath();
        String base = oldContext.getBase();
        boolean reloadable = oldContext.isReloadable();
        oldContext.stop();
        LogFactory.get().info("开始重新部署 web 应用： {} ", oldContext.getBase());
        this.contextMap.remove(path);
        Context newContext = new Context(path, base, this, reloadable);
        this.contextMap.put(newContext.getPath(), newContext);
        LogFactory.get().info("完成部署 web 应用： {} ", newContext.getBase());
    }

    public String getName() {
        return name;
    }

    public String getAppBase() {
        return appBase;
    }

    public String getAbsoluteAppBase() {
        return this.absoluteAppBase;
    }

    public Map<String, Context> getContextMap() {
        return contextMap;
    }
}
